package pw.goyd.game.model;

import pw.goyd.db.RedisUtil;
import pw.goyd.game.api.CalcGolds;
import pw.goyd.game.constant.setting.Command;
import pw.goyd.game.constant.setting.GameSetting;
import pw.goyd.game.constant.setting.StateCode;
import pw.goyd.game.handler.imp.EXITROOM;
import pw.goyd.game.logic.PubDeclarerResponse;
import pw.goyd.game.logic.ShowCardsResponse;
import pw.goyd.game.logic.TimeDownResponse;
import pw.goyd.game.logic.UpdateMoneyResponse;
import pw.goyd.game.manager.RoomManager;
import pw.goyd.game.server.Log;
import pw.goyd.game.server.Server;
import pw.goyd.protocol.model.Response;
import pw.goyd.subscribe.PlayerCustomer;

import java.util.*;

/**
 * 房间基础
 *
 * @author StanWind
 */
public class Room implements GameSetting {
    //随机数种子
    private static Random rdm;
    //座位
    public List<Seat> seats;
    //离开的玩家
    public Set<PlayerCustomer> leaveList = new HashSet<>();
    //房间ID
    private int roomID;
    //底分
    private int leastSocre;
    //进房金币下限
    private int leastGold;
    //正在游戏
    private boolean isGame = false;
    //准备开始计时
    private int readyTime = -1;
    //当前步骤
    private int step = StateCode.STEP_READY;
    //扑克牌
    private List<Card> cards;
    //庄家
    private PlayerCustomer declarerPlayer;
    //正在游戏的玩家
    private List<PlayerCustomer> isPlayingPlayer;
    //是否结算完毕
    private boolean isCalcGolds;

    /**
     * 初始化五个座位
     */
    public Room() {

        seats = new ArrayList<>();
        for (int i = 0; i < GameSetting.MAXTABLESEAT; i++)
            seats.add(new Seat());

        rdm = new Random(System.currentTimeMillis());
        //initCards();

    }

    public static Random getRdm() {
        return rdm;
    }

    public static void setRdm(Random rdm) {
        Room.rdm = rdm;
    }

    public boolean isCalcGolds() {
        return isCalcGolds;
    }

    public void setCalcGolds(boolean calcGolds) {
        isCalcGolds = calcGolds;
    }

    public List<PlayerCustomer> getIsPlayingPlayer() {
        return isPlayingPlayer;
    }

    public void setIsPlayingPlayer(List<PlayerCustomer> isPlayingPlayer) {
        this.isPlayingPlayer = isPlayingPlayer;
    }

    public PlayerCustomer getDeclarerPlayer() {
        return declarerPlayer;
    }

    public void setDeclarerPlayer(PlayerCustomer declarerPlayer) {
        this.declarerPlayer = declarerPlayer;
    }

    public int getStep() {
        return step;
    }

    public void setStep(int step) {
        this.step = step;
    }

    public List<Card> getCards() {
        return cards;
    }

    public void setCards(List<Card> cards) {
        this.cards = cards;
    }

    public void setSeats(List<Seat> seats) {
        this.seats = seats;
    }

    public boolean isGame() {
        return isGame;
    }

    public void setGame(boolean isGame) {
        this.isGame = isGame;
    }

    public int getReadyTime() {
        return readyTime;
    }

    public void setReadyTime(int readyTime) {
        this.readyTime = readyTime;
    }

    public int getRoomID() {
        return roomID;
    }

    public void setRoomID(int roomID) {
        this.roomID = roomID;
    }

    public int getLeastSocre() {
        return leastSocre;
    }

    public void setLeastSocre(int leastSocre) {
        this.leastSocre = leastSocre;
    }

    public int getLeastGold() {
        return leastGold;
    }

    public void setLeastGold(int leastGold) {
        this.leastGold = leastGold;
    }

    public List<Seat> getSeats() {
        return seats;
    }

    public void setSeats(ArrayList<Seat> seats) {
        this.seats = seats;
    }

    public void initCards() {
        //扑克牌初始化
        cards = new ArrayList<>();
        for (int i = 0; i < 13; i++) {
            for (int j = 0; j < 4; j++) {
                Card card = new Card();
                card.setSuit(j);
                card.setWeight(i);
                cards.add(card);
            }
        }
    }

    /**
     * 结算金币
     */
    public void calcGolds() {
        CalcGolds.settleAccounts(getIsPlayingPlayer());
        for (Seat s : seats) {
            PlayerCustomer p = s.getPlayer();
            if (p != null)
                p.setGold(p.getGold() + p.getChangingGolds());
        }
        setCalcGolds(true);
    }

    /**
     * 获取房间玩家人数
     */
    public int getPlayerCount() {
        int Count = 0;
        for (Seat s : seats) {
            if (s.getPlayer() != null)
                Count++;
        }
        return Count;
    }

    /**
     * 获取随机牌
     *
     * @return
     */
    public Card getRandCard() {
        int cardsCount = cards.size();
        int index = rdm.nextInt(cardsCount);
        Card c = cards.get(index);
        cards.remove(index);
        return c;
    }

    /**
     * 推送庄家
     */
    public void pubDeclarer() {
        PubDeclarerResponse pubDeclarerResponse = new PubDeclarerResponse();
        pubDeclarerResponse.setPlayerCustomer(declarerPlayer);
        Response response = new Response();
        response.setCmd(Command.CMD_PUBDECLARER);
        response.setData(pubDeclarerResponse.getBytes());
        response.setTime(0);
        RedisUtil.pubRoom(this.getRoomID(), response.getAllBytes());
    }

    /**
     * 推送所有玩家手牌
     */
    public void pubShowCards() {
        ShowCardsResponse showCardsResponse = new ShowCardsResponse();
        showCardsResponse.setPl(isPlayingPlayer);
        Response response = new Response();
        response.setCmd(Command.CMD_SHOWCARDS);
        response.setData(showCardsResponse.getBytes());
        response.setTime(0);
        RedisUtil.pubRoom(this.getRoomID(), response.getAllBytes());
    }

    /**
     * 推送玩家金币
     */
    public void pubGolds() {
        UpdateMoneyResponse updateMoneyResponse = new UpdateMoneyResponse();
        updateMoneyResponse.setPl(isPlayingPlayer);
        Response response = new Response();
        response.setCmd(Command.CMD_UPDATEMONEY);
        response.setData(updateMoneyResponse.getBytes());
        response.setTime(0);
        RedisUtil.pubRoom(this.getRoomID(), response.getAllBytes());
    }

    /**
     * 获取倒计时包 可以给掉线玩家单独推送
     */
    public Response getTimeDownPack() {
        TimeDownResponse timeDownResponse = new TimeDownResponse();
        timeDownResponse.setTime(readyTime + READY_TIME - Server.getServerTime());
        timeDownResponse.setStep(getStep());
        Response response = new Response();
        response.setCmd(Command.CMD_TIMEDOWN);
        response.setData(timeDownResponse.getBytes());
        response.setTime(0);
        return response;
    }

    /**
     * 推送倒计时
     */
    public void pubTimeDown() {
        RedisUtil.pubRoom(this.getRoomID(), getTimeDownPack().getAllBytes());
    }

    /**
     * 扣除牌桌费
     * 公式 底分^2 * 全局倍数
     */
    public void deductTableFee() {
        for (PlayerCustomer p : isPlayingPlayer) {
            p.setGold(p.getGold() - getLeastSocre() * GameSetting.GLOBAL_MONEY);
        }

    }

    /**
     * 清除玩家手牌
     */
    public void clearCards() {
        for (PlayerCustomer p : isPlayingPlayer) {
            p.setCards(null);
        }
    }

    /**
     * 处理游戏结束任务队列 踢出金币不够玩家
     * 例如可以把中途玩家退出的包放在这
     */
    public void handleTask() {
        Log.getLogger().info("开始处理中途退出---->" + leaveList.size());
        for (PlayerCustomer p : leaveList) {
            RoomManager.leaveRoom(p);
        }
        leaveList = new HashSet<>();

        for (Seat s : seats) {
            if (s.getPlayer() != null) {
                //  踢出金币不足玩家
                if (s.getPlayer().getGold() < GameSetting.MIN_ROOM_MONEY) {
                    s.getPlayer().sendKickOutRoom();    //  不允许进入
                    EXITROOM.process(s.getPlayer());    //  退出房间
                    if (s.getPlayer() != null)
                        Log.getLogger().info("金币不足 踢出玩家[" + s.getPlayer().getNickname() + "]");
                }
                //  踢出下线玩家
                if (!s.getPlayer().getChannel().isOpen() || !s.getPlayer().getChannel().isWritable()) {
                    Log.getLogger().info("不可到达 踢出玩家[" + s.getPlayer().getNickname() + "]");
                    EXITROOM.process(s.getPlayer());
                }
            }
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("RoomID:" + roomID + "\t");
        sb.append("isGame:" + readyTime + "\t");
        sb.append("Step:" + step + "\t");
        if (!isGame())
            return sb.toString();
        sb.append("Declarer:" + declarerPlayer.getNickname() + "\t");
        int count = 0;
        for (PlayerCustomer p : isPlayingPlayer) {
            count++;
            sb.append("Player" + count + ":" + p.getNickname() + "\t");
        }
        return sb.toString();
    }
}
